package dasregistry.utils;

import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.File;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.SQLException;
import java.util.HashMap;
import java.util.Iterator;

import org.biojava.services.das.dao.DasSourceManager;
import org.springframework.beans.factory.BeanFactory;
import org.springframework.context.support.ClassPathXmlApplicationContext;

/**
 * class for getting data from ncbi taxonomy flat files then generating species and subspecies entries in the registry database
 * from the ncbi taxonomy tree.
 * 
 * @author jw12
 * 
 */
public class CreateOrganisms {

	/**
	 * @param args
	 */
	public static void main(String[] args) {

		String names = "/.automount/evs-ssg/root/web/jw12/taxonomy/names.dmp";
		String nodes = "/.automount/evs-ssg/root/web/jw12/taxonomy/nodes.dmp";
		String output = "/.automount/evs-ssg/root/web/jw12/taxonomy/organism.txt";
		String organismsAlreadyInRegistry = "/.automount/evs-ssg/root/web/jw12/taxonomy/registry_organism_dump.txt";

		CreateOrganisms co = new CreateOrganisms(names, nodes, output,
				organismsAlreadyInRegistry);

	}

	public CreateOrganisms(String names, String nodes, String output,
			String organismsAlreadyInRegistry) {

		// get unique taxon_ids with species or subspecies as their rank i.e.
		// kingdom or species and add them to a hash if species
		HashMap species = new HashMap();
		HashMap speciesAndSciNames = new HashMap();
		HashMap speciesAndCommonNames = new HashMap();
		HashMap speciesOtherNameNotCommon = new HashMap();
		HashMap alreadyInRegistry = new HashMap();
		int orgsFoundToBeInRegistry = 0;// at end of program should be same as
										// in alreadyInRegistryHashmap.size
		BeanFactory ctx=(new ClassPathXmlApplicationContext("SpringDAO.xml"));
		DasSourceManager dataManager=(DasSourceManager) ctx.getBean("dasSourceManager");
		Connection conn=this.getConnection();
		
		BufferedWriter out=null;

		try {
			out = new BufferedWriter(new FileWriter(output));
			
		} catch (IOException e) {
			e.printStackTrace();
		}

		
		
		
		
		
		
		
		
		
		try {
			BufferedReader in = new BufferedReader(new FileReader(nodes));
			String str;
			while ((str = in.readLine()) != null) {
				// System.out.println("nodes line="+str);
				String[] fields = str.split("\\|");
				String taxid = fields[0].trim();
				String rank = fields[2].trim();
				// System.out.println("taxid "+taxid+" rank"+rank);
				if (rank.contains("species")) {
					if (species.containsKey(taxid)) {
						// System.out.println("contains taxid already "+taxid+" rank"+rank);
					}
					// System.out.println("putting taxid="+taxid+",rank="+rank+", into list");
					species.put(taxid, rank);
				}
			}
			in.close();
		} catch (IOException e) {
			e.printStackTrace();
		}

		try {
			BufferedReader in = new BufferedReader(new FileReader(names));
			String str;
			while ((str = in.readLine()) != null) {

				// System.out.println("names line="+str);
				String[] fields = str.split("\\|");
				String taxid = fields[0].trim();
				String name = fields[1].trim();
				String type = fields[3].trim();

				if (species.containsKey(taxid)) {
					if (type.equals("scientific name")) {
						// System.out.println("taxid,"+taxid+",found in species with name="+name+",type="+type);
						speciesAndSciNames.put(taxid, name);
					} else if (type.equals("common name")) {
						// System.out.println("taxid,"+taxid+",found in species with common name="+name+",type="+type);
						speciesAndCommonNames.put(taxid, name);
					} else if (type.equalsIgnoreCase("genbank common name")
							|| type.equalsIgnoreCase("synonym")) {
						speciesOtherNameNotCommon.put(taxid, name);
					}
				}

			}
			in.close();
		} catch (IOException e) {
			e.printStackTrace();
		}

		// Read organisms that are already in the registry
		try {
			BufferedReader in = new BufferedReader(new FileReader(
					organismsAlreadyInRegistry));
			String str;
			while ((str = in.readLine()) != null) {
				// System.out.println("names line="+str);
				String[] fields = str.split("\\t");
				String taxid = fields[3].trim();
				alreadyInRegistry.put(taxid, "");

			}
			in.close();
		} catch (IOException e) {
			e.printStackTrace();
		}

		// as a quick hack we can print the species our in their order of taxid
		// by readint the first file again which is in taxid order
		int i = 0;
		try {
			BufferedReader in = new BufferedReader(new FileReader(nodes));
			String str;
			while ((str = in.readLine()) != null) {

				String[] fields = str.split("\\|");
				String taxid = fields[0].trim();
				if (species.containsKey(taxid)) {
					if (alreadyInRegistry.containsKey(taxid)) {
						orgsFoundToBeInRegistry++;
						alreadyInRegistry.remove(taxid);
						//don't print as we don't wont to override or change auto_ids already set by registry
					} else {
						String sciName = speciesAndSciNames.get(taxid)
								.toString();
						String commonName = "null";
						if (speciesAndCommonNames.containsKey(taxid)) {
							commonName = speciesAndCommonNames.get(taxid)
									.toString();
						} else if (speciesOtherNameNotCommon.containsKey(taxid)) {
							commonName = speciesOtherNameNotCommon.get(taxid)
									.toString();
						}

						this.createOrganism(conn,sciName,commonName,taxid );
						//out.write(taxid + "\t" + commonName + "\t"
								//+ sciName+"\n");
						i++;
					}
				}
			}
			in.close();
			out.flush();
			out.close();
		} catch (IOException e) {
			e.printStackTrace();
		}

		// Iterator iterator = species.keySet().iterator();
		// int i=0;
		// while (iterator.hasNext()) {
		// String key = iterator.next().toString();
		// String sciName = speciesAndSciNames.get(key).toString();
		// String commonName="-";
		// if(speciesAndCommonNames.containsKey(key))commonName=
		// speciesAndCommonNames.get(key).toString();
		//	      
		// System.out.println(key + " " + sciName+" "+commonName);
		// i++;
		// }
		//		

		System.out.println("species hasmap size=" + species.size());
		System.out.println("speciesAndSciNames hasmap size="
				+ speciesAndSciNames.size());
		System.out.println("speciesAndCommonNames hasmap size="
				+ speciesAndCommonNames.size());
		System.out.println("speciesAndNotCommonNames hashmap size="
				+ speciesOtherNameNotCommon.size());
		System.out.println("alreadyInRegistryHash.length="
				+ alreadyInRegistry.size()
				+ " organisms detected that are already in registry"
				+ orgsFoundToBeInRegistry);
		System.out.println("number of species printed out=" + i);
		System.out.println("organisms with taxids in the registry but not in the ncbi file:"+alreadyInRegistry.toString());

	}
	
	private void createOrganism(Connection conn, String scientificName, String commonName , String taxId) {
		BeanFactory ctx=(new ClassPathXmlApplicationContext("SpringDAO.xml"));
		DasSourceManager dao=(DasSourceManager) ctx.getBean("dasSourceManager");
		
		//check to see if organism name exists already before updating
			String[]name={scientificName};
			Integer[] taxidsKnown;
			try {
				taxidsKnown = dao.getTaxIds(conn,name);
				if(taxidsKnown.length>0){
					System.out.println("Scientific Name already exists in database!!! "+scientificName);
				}else{
					dao.createOrganism(conn, commonName, scientificName, Integer.parseInt(taxId));
				}
			} catch (SQLException e) {
				if ( conn != null ) {
					try {
						conn.close();
					} catch ( SQLException ex) {
						ex.printStackTrace();
					}
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
			
			}
	}

			
			
			private Connection getConnection(){
				Connection connection = null;
			    try {
			        // Load the JDBC driver
			    	
			        String driverName = "com.mysql.jdbc.Driver"; // MySQL MM JDBC driver
			        Class.forName(driverName);
			    
			        // Create a connection to the database
			        String serverName = "mcs4a:3307";
			        String mydatabase = "jw12_dasregistry02";
			        String url = "jdbc:mysql://" + serverName +  "/" + mydatabase; // a JDBC url
			        String username = "jw12";
			        String password = "jw12";
			        connection = DriverManager.getConnection(url, username, password);
			        
			    } catch (ClassNotFoundException e) {
			        // Could not find the database driver
			    	e.printStackTrace();
			    } catch (SQLException e) {
			        // Could not connect to the database
			    	e.printStackTrace();
			    }
			    return connection;
			}
}
